<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    <meta name="description" content="Hexo Theme Redefine">
    <meta name="author" content="Sakura">
    
    <title>
        
            吃透JAVA_Stream流操作 |
        
        Sakura Blog
    </title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link rel="preconnect" href="https://evan.beee.top" crossorigin>
    
<link rel="stylesheet" href="/sakura-blog/css/style.css">

    <link rel="shortcut icon" href="/sakura-blog/images/bitbug_favicon.ico">
    
<link rel="stylesheet" href="/sakura-blog/css/fontawesome.min.css">

    
<link rel="stylesheet" href="/sakura-blog/css/brands.min.css">

    
<link rel="stylesheet" href="/sakura-blog/css/solid.min.css">

    
<link rel="stylesheet" href="/sakura-blog/css/regular.min.css">

    
    
    
    
<link rel="stylesheet" href="/sakura-blog/css/css2.css">

    <script id="hexo-configurations">
    let REDEFINE = window.REDEFINE || {};
    REDEFINE.hexo_config = {"hostname":"xindong_a.gitee.io","root":"/sakura-blog/","language":"zh-CN"};
    REDEFINE.theme_config = {"toc":{"enable":true,"number":false,"expand_all":true,"init_open":true},"style":{"primary_color":"#005080","avatar":"/images/avatar.jpg","favicon":"/images/bitbug_favicon.ico","article_img_align":"center","right_side_width":"210px","content_max_width":"1000px","nav_color":{"left":"#f78736","right":"#367df7","transparency":35},"hover":{"shadow":true,"scale":false},"first_screen":{"enable":true,"background_image":{"light":"https://evan.beee.top/img/wallhaven-wqery6-light.webp","dark":"https://evan.beee.top/img/wallhaven-wqery6-dark.webp"},"title_color":{"light":"#fff","dark":"#d1d1b6"},"description":"宁静致远"},"scroll":{"progress_bar":{"enable":true},"percent":{"enable":false}}},"local_search":{"enable":false,"preload":true},"code_block":{"copy":true,"style":"mac"},"pjax":{"enable":true},"lazyload":{"enable":true},"version":"0.4.6","friend_links":{"columns":2}};
    REDEFINE.language_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
  </script>
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
<div class="progress-bar-container">
    
        <span class="scroll-progress-bar"></span>
    

    
        <span class="pjax-progress-bar"></span>
        <span class="pjax-progress-icon">
            <i class="fa-solid fa-circle-notch fa-spin"></i>
        </span>
    
</div>


<main class="page-container">

    

    <div class="page-main-content">

        <div class="page-main-content-top">
            <header class="header-wrapper">
    
    <div class="header-content">
        <div class="left">
            
            <a class="logo-title" href="/">
                Sakura Blog
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="pc">
                <ul class="menu-list">
                    
                        <li class="menu-item">
                            <!-- Menu -->
                            <a class="" 
                                href="/sakura-blog/" >
                                
                                    
                                        <i class="fa-regular fa-house"></i>
                                    
                                    首页
                                
                            </a>
                            <!-- Submenu -->
                            
                        </li>
                    
                        <li class="menu-item">
                            <!-- Menu -->
                            <a class="" 
                                href="/sakura-blog/archives" >
                                
                                    
                                        <i class="fa-regular fa-archive"></i>
                                    
                                    归档
                                
                            </a>
                            <!-- Submenu -->
                            
                        </li>
                    
                        <li class="menu-item">
                            <!-- Menu -->
                            <a class="" 
                                target="_blank" rel="noopener" href="https://status.evanluo.top/" >
                                
                                    
                                        <i class="fa-regular fa-chart-bar"></i>
                                    
                                    状态
                                
                            </a>
                            <!-- Submenu -->
                            
                        </li>
                    
                        <li class="menu-item">
                            <!-- Menu -->
                            <a class="has-dropdown" 
                                href="javascript:void(0);">
                                
                                    
                                        <i class="fa-regular fa-user"></i>
                                    
                                    关于&nbsp;<i class="fa-solid fa-chevron-down"></i>
                                
                            </a>
                            <!-- Submenu -->
                            
                                <ul class="sub-menu">
                                  
                                    <li>
                                      <a href="/sakura-blog/about">ME
                                      </a>
                                    </li>
                                  
                                    <li>
                                      <a target="_blank" rel="noopener" href="https://github.com/EvanNotFound/hexo-theme-redefine">GITHUB
                                      </a>
                                    </li>
                                  
                                    <li>
                                      <a target="_blank" rel="noopener" href="https://www.evanluo.top">BLOG
                                      </a>
                                    </li>
                                  
                                    <li>
                                      <a href="/sakura-blog/friends">FRIENDS
                                      </a>
                                    </li>
                                  
                                </ul>
                            
                        </li>
                    
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                <div class="icon-item menu-bar">
                    <div class="menu-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile drawer -->
    <div class="header-drawer">
        <ul class="drawer-menu-list">
            
                <li class="drawer-menu-item flex-center">
                    <a class="" 
                       href="/sakura-blog/" >
                         
                            
                                <i class="fa-regular fa-house"></i>
                            
                            首页
                        
                    </a>
                </li>
                <!-- Submenu -->
                
            
                <li class="drawer-menu-item flex-center">
                    <a class="" 
                       href="/sakura-blog/archives" >
                         
                            
                                <i class="fa-regular fa-archive"></i>
                            
                            归档
                        
                    </a>
                </li>
                <!-- Submenu -->
                
            
                <li class="drawer-menu-item flex-center">
                    <a class="" 
                       target="_blank" rel="noopener" href="https://status.evanluo.top/" >
                         
                            
                                <i class="fa-regular fa-chart-bar"></i>
                            
                            状态
                        
                    </a>
                </li>
                <!-- Submenu -->
                
            
                <li class="drawer-menu-item flex-center">
                    <a class="has-dropdown" 
                       href="javascript:void(0);">
                        
                            
                                <i class="fa-regular fa-user"></i>
                            
                            关于&nbsp;<i class="fa-solid fa-chevron-down"></i>
                        
                    </a>
                </li>
                <!-- Submenu -->
                          
                    
                        <li class="dropdown-item flex-center">
                            <a class="dropdown-item" href="/sakura-blog/about">ME</a>
                        </li>
                    
                        <li class="dropdown-item flex-center">
                            <a class="dropdown-item" target="_blank" rel="noopener" href="https://github.com/EvanNotFound/hexo-theme-redefine">GITHUB</a>
                        </li>
                    
                        <li class="dropdown-item flex-center">
                            <a class="dropdown-item" target="_blank" rel="noopener" href="https://www.evanluo.top">BLOG</a>
                        </li>
                    
                        <li class="dropdown-item flex-center">
                            <a class="dropdown-item" href="/sakura-blog/friends">FRIENDS</a>
                        </li>
                    
                
            
        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="page-main-content-middle">

            <div class="main-content">

                
                    <div class="fade-in-down-animation">
    <div class="post-page-container">
        <div class="article-content-container">
            <div class="article-title">
                <span class="title-hover-animation"><h1 style="font-size:2rem; font-weight: bold; margin: 10px 0;">吃透JAVA_Stream流操作</h1></span>
            </div>

            
                <div class="article-header">
                    <div class="avatar">
                        <img src="/sakura-blog/images/avatar.jpg">
                    </div>
                    <div class="info">
                        <div class="author">
                            <span class="name">Sakura</span>
                            
                                <span class="author-label">lol</span>
                            
                        </div>
                        <div class="meta-info">
                            <div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="pc">2023-01-09 11:25:27</span>
        <span class="mobile">2023-01-09 11:25</span>
    </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/sakura-blog/tags/java/">java</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

                        </div>
                    </div>
                </div>
            

            <div class="article-content markdown-body">
                <p>大家好，我是Sakura。在JAVA中，涉及到对<code>数组</code>、<code>Collection</code>等集合类中的元素进行操作的时候，通常会通过<strong>循环的方式</strong>进行逐个处理，或者<strong>使用Stream</strong>的方式进行处理。</p>
<hr>
<p>好了，废话不多说，上才艺</p>
<p>例如，现在有这么一个需求：<em><strong>从给定句子中返回单词长度大于5的单词列表，按长度倒序输出，最多返回3个</strong></em></p>
<p>在<strong>JAVA7及之前</strong>的代码中，我们会可以照如下的方式进行实现：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 【常规方式】</span></span><br><span class="line"><span class="comment"> * 从给定句子中返回单词长度大于5的单词列表，按长度倒序输出，最多返回3个</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> sentence 给定的句子，约定非空，且单词之间仅由一个空格分隔</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 倒序输出符合条件的单词列表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> List&lt;String&gt; <span class="title function_">sortGetTop3LongWords</span><span class="params">(<span class="meta">@NotNull</span> String sentence)</span> &#123;</span><br><span class="line">    <span class="comment">// 先切割句子，获取具体的单词信息</span></span><br><span class="line">    String[] words = sentence.split(<span class="string">&quot; &quot;</span>);</span><br><span class="line">    List&lt;String&gt; wordList = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    <span class="comment">// 循环判断单词的长度，先过滤出符合长度要求的单词</span></span><br><span class="line">    <span class="keyword">for</span> (String word : words) &#123;</span><br><span class="line">        <span class="keyword">if</span> (word.length() &gt; <span class="number">5</span>) &#123;</span><br><span class="line">            wordList.add(word);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 对符合条件的列表按照长度进行排序</span></span><br><span class="line">    wordList.sort((o1, o2) -&gt; o2.length() - o1.length());</span><br><span class="line">    <span class="comment">// 判断list结果长度，如果大于3则截取前三个数据的子list返回</span></span><br><span class="line">    <span class="keyword">if</span> (wordList.size() &gt; <span class="number">3</span>) &#123;</span><br><span class="line">        wordList = wordList.subList(<span class="number">0</span>, <span class="number">3</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> wordList;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>在<strong>JAVA8及之后</strong>的版本中，借助Stream流，我们可以更加优雅的写出如下代码：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 【Stream方式】</span></span><br><span class="line"><span class="comment">    * 从给定句子中返回单词长度大于5的单词列表，按长度倒序输出，最多返回3个</span></span><br><span class="line"><span class="comment">    *</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> sentence 给定的句子，约定非空，且单词之间仅由一个空格分隔</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> 倒序输出符合条件的单词列表</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">sortGetTop3LongWordsByStream</span><span class="params">(<span class="meta">@NotNull</span> String sentence)</span> &#123;</span><br><span class="line">       <span class="keyword">return</span> Arrays.stream(sentence.split(<span class="string">&quot; &quot;</span>))</span><br><span class="line">               .filter(word -&gt; word.length() &gt; <span class="number">5</span>)</span><br><span class="line">               .sorted((o1, o2) -&gt; o2.length() - o1.length())</span><br><span class="line">               .limit(<span class="number">3</span>)</span><br><span class="line">               .collect(Collectors.toList());</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></div>

<p>直观感受上，<code>Stream</code>的实现方式代码更加简洁、一气呵成。很多的同学在代码中也经常使用Stream流，但是对Stream流的认知往往也是仅限于会一些简单的<code>filter</code>、<code>map</code>、<code>collect</code>等操作，但JAVA的Stream可以适用的场景与能力远不止这些</p>
<p>那么问题来了：<strong>Stream相较于传统的foreach的方式处理stream，到底有啥优势</strong>？</p>
<p>这里我们可以先搁置这个问题，先整体全面的了解下Stream，然后再来讨论下这个问题。</p>
<h3 id="Stream初相识"><a href="#Stream初相识" class="headerlink" title="Stream初相识"></a>Stream初相识</h3><p>概括讲，可以将Stream流操作分为<strong>3种类型</strong>：</p>
<ul>
<li>创建Stream</li>
<li>Stream中间处理</li>
<li>终止Steam</li>
</ul>
<p><strong><img lazyload src="/images/loading.svg" data-src="/sakura-blog/2023/01/09/%E5%90%83%E9%80%8FJAVA-Stream%E6%B5%81%E6%93%8D%E4%BD%9C/01.png" class title="图片"></strong></p>
<p>每个Stream管道操作类型都包含若干API方法，先列举下各个API方法的功能介绍。</p>
<ul>
<li><strong>开始管道</strong></li>
</ul>
<p>主要负责新建一个Stream流，或者基于现有的数组、List、Set、Map等集合类型对象创建出新的Stream流。</p>
<table>
<thead>
<tr>
<th><strong>API</strong></th>
<th><strong>功能说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>stream()</td>
<td>创建出一个新的stream串行流对象</td>
</tr>
<tr>
<td>parallelStream()</td>
<td>创建出一个可并行执行的stream流对象</td>
</tr>
<tr>
<td>Stream.of()</td>
<td>通过给定的一系列元素创建一个新的Stream串行流对象</td>
</tr>
</tbody></table>
<ul>
<li><strong>中间管道</strong></li>
</ul>
<p>负责对Stream进行处理操作，并返回一个新的Stream对象，中间管道操作可以进行<strong>叠加</strong>。</p>
<table>
<thead>
<tr>
<th>API</th>
<th><strong>功能说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>filter()</td>
<td>按照条件过滤符合要求的元素， 返回新的stream流</td>
</tr>
<tr>
<td>map()</td>
<td>将已有元素转换为另一个对象类型，一对一逻辑，返回新的stream流</td>
</tr>
<tr>
<td>flatMap()</td>
<td>将已有元素转换为另一个对象类型，一对多逻辑，即原来一个元素对象可能会转换为1个或者多个新类型的元素，返回新的stream流</td>
</tr>
<tr>
<td>limit()</td>
<td>仅保留集合前面指定个数的元素，返回新的stream流</td>
</tr>
<tr>
<td>skip()</td>
<td>跳过集合前面指定个数的元素，返回新的stream流</td>
</tr>
<tr>
<td>concat()</td>
<td>将两个流的数据合并起来为1个新的流，返回新的stream流</td>
</tr>
<tr>
<td>distinct()</td>
<td>对Stream中所有元素进行去重，返回新的stream流</td>
</tr>
<tr>
<td>sorted()</td>
<td>对stream中所有的元素按照指定规则进行排序，返回新的stream流</td>
</tr>
<tr>
<td>peek()</td>
<td>对stream流中的每个元素进行逐个遍历处理，返回处理后的stream流</td>
</tr>
</tbody></table>
<ul>
<li><strong>终止管道</strong></li>
</ul>
<p>顾名思义，通过终止管道操作之后，Stream流将<strong>会结束</strong>，最后可能会执行某些逻辑处理，或者是按照要求返回某些执行后的结果数据。</p>
<table>
<thead>
<tr>
<th>API</th>
<th><strong>功能说明</strong></th>
</tr>
</thead>
<tbody><tr>
<td>count()</td>
<td>返回stream处理后最终的元素个数</td>
</tr>
<tr>
<td>max()</td>
<td>返回stream处理后的元素最大值</td>
</tr>
<tr>
<td>min()</td>
<td>返回stream处理后的元素最小值</td>
</tr>
<tr>
<td>findFirst()</td>
<td>找到第一个符合条件的元素时则终止流处理</td>
</tr>
<tr>
<td>findAny()</td>
<td>找到任何一个符合条件的元素时则退出流处理，这个<strong>对于串行流时与findFirst相同，对于并行流时比较高效</strong>，任何分片中找到都会终止后续计算逻辑</td>
</tr>
<tr>
<td>anyMatch()</td>
<td>返回一个boolean值，类似于isContains(),用于判断是否有符合条件的元素</td>
</tr>
<tr>
<td>allMatch()</td>
<td>返回一个boolean值，用于判断是否所有元素都符合条件</td>
</tr>
<tr>
<td>noneMatch()</td>
<td>返回一个boolean值， 用于判断是否所有元素都不符合条件</td>
</tr>
<tr>
<td>collect()</td>
<td>将流转换为指定的类型，通过Collectors进行指定</td>
</tr>
<tr>
<td>toArray()</td>
<td>将流转换为数组</td>
</tr>
<tr>
<td>iterator()</td>
<td>将流转换为Iterator对象</td>
</tr>
<tr>
<td>foreach()</td>
<td>无返回值，对元素进行逐个遍历，然后执行给定的处理逻辑</td>
</tr>
</tbody></table>
<h3 id="map与flatMap"><a href="#map与flatMap" class="headerlink" title="map与flatMap"></a>map与flatMap</h3><p><code>map</code>与<code>flatMap</code>都是用于转换已有的元素为其它元素，区别点在于：</p>
<ul>
<li>map <strong>必须是一对一的</strong>，即每个元素都只能转换为1个新的元素</li>
<li>flatMap <strong>可以是一对多的</strong>，即每个元素都可以转换为1个或者多个新的元素</li>
</ul>
<p><strong><img lazyload src="/images/loading.svg" data-src="/sakura-blog/2023/01/09/%E5%90%83%E9%80%8FJAVA-Stream%E6%B5%81%E6%93%8D%E4%BD%9C/02.png" class title="图片"></strong></p>
<p>比如：<strong>有一个字符串ID列表，现在需要将其转为User对象列表</strong>。可以使用map来实现：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 演示map的用途：一对一转换</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">stringToIntMap</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>,<span class="string">&quot;105&quot;</span>,<span class="string">&quot;308&quot;</span>,<span class="string">&quot;469&quot;</span>,<span class="string">&quot;627&quot;</span>,<span class="string">&quot;193&quot;</span>,<span class="string">&quot;111&quot;</span>);</span><br><span class="line">    <span class="comment">// 使用流操作</span></span><br><span class="line">    List&lt;Integer&gt; results = ids.stream()</span><br><span class="line">            .map(s -&gt; Integer.valueOf(s))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    System.out.println(results);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>执行之后，会发现每一个元素都被转换为对应新的元素，但是前后总元素个数是一致的：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[User&#123;id=&#x27;205&#x27;&#125;, </span><br><span class="line"> User&#123;id=&#x27;105&#x27;&#125;,</span><br><span class="line"> User&#123;id=&#x27;308&#x27;&#125;, </span><br><span class="line"> User&#123;id=&#x27;469&#x27;&#125;, </span><br><span class="line"> User&#123;id=&#x27;627&#x27;&#125;, </span><br><span class="line"> User&#123;id=&#x27;193&#x27;&#125;, </span><br><span class="line"> User&#123;id=&#x27;111&#x27;&#125;]</span><br></pre></td></tr></table></figure></div>

<p>再比如：<strong>现有一个句子列表，需要将句子中每个单词都提取出来得到一个所有单词列表</strong>。这种情况用map就搞不定了，需要<code>flatMap</code>上场了：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">stringToIntFlatmap</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; sentences = Arrays.asList(<span class="string">&quot;hello world&quot;</span>,<span class="string">&quot;Jia Gou Wu Dao&quot;</span>);</span><br><span class="line">    <span class="comment">// 使用流操作</span></span><br><span class="line">    List&lt;String&gt; results = sentences.stream()</span><br><span class="line">            .flatMap(sentence -&gt; Arrays.stream(sentence.split(<span class="string">&quot; &quot;</span>)))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    System.out.println(results);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>执行结果如下，可以看到结果列表中元素个数是比原始列表元素个数要多的：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[hello, world, Jia, Gou, Wu, Dao]</span><br></pre></td></tr></table></figure></div>

<p>这里需要补充一句，<code>flatMap</code>操作的时候其实是先每个元素处理并返回一个新的Stream，然后将多个Stream展开合并为了一个完整的新的Stream，如下：</p>
<p><strong><img lazyload src="/images/loading.svg" data-src="/sakura-blog/2023/01/09/%E5%90%83%E9%80%8FJAVA-Stream%E6%B5%81%E6%93%8D%E4%BD%9C/03.png" class title="图片"></strong></p>
<h3 id="peek和foreach方法"><a href="#peek和foreach方法" class="headerlink" title="peek和foreach方法"></a>peek和foreach方法</h3><p><code>peek</code>和<code>foreach</code>，都可以用于对元素进行遍历然后逐个的进行处理。</p>
<p>但根据前面的介绍，<strong>peek属于中间方法</strong>，而<strong>foreach属于终止方法</strong>。这也就意味着peek只能作为管道中途的一个处理步骤，而没法直接执行得到结果，其后面必须还要有其它终止操作的时候才会被执行；而foreach作为无返回值的终止方法，则可以直接执行相关操作。</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testPeekAndforeach</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; sentences = Arrays.asList(<span class="string">&quot;hello world&quot;</span>,<span class="string">&quot;Jia Gou Wu Dao&quot;</span>);</span><br><span class="line">    <span class="comment">// 演示点1： 仅peek操作，最终不会执行</span></span><br><span class="line">    System.out.println(<span class="string">&quot;----before peek----&quot;</span>);</span><br><span class="line">    sentences.stream().peek(sentence -&gt; System.out.println(sentence));</span><br><span class="line">    System.out.println(<span class="string">&quot;----after peek----&quot;</span>);</span><br><span class="line">    <span class="comment">// 演示点2： 仅foreach操作，最终会执行</span></span><br><span class="line">    System.out.println(<span class="string">&quot;----before foreach----&quot;</span>);</span><br><span class="line">    sentences.stream().forEach(sentence -&gt; System.out.println(sentence));</span><br><span class="line">    System.out.println(<span class="string">&quot;----after foreach----&quot;</span>);</span><br><span class="line">    <span class="comment">// 演示点3：peek操作后面增加终止操作，peek会执行</span></span><br><span class="line">    System.out.println(<span class="string">&quot;----before peek and count----&quot;</span>);</span><br><span class="line">    sentences.stream().peek(sentence -&gt; System.out.println(sentence)).count();</span><br><span class="line">    System.out.println(<span class="string">&quot;----after peek and count----&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>输出结果可以看出，peek独自调用时并没有被执行、但peek后面加上终止操作之后便可以被执行，而foreach可以直接被执行：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">----before peek----</span><br><span class="line">----after peek----</span><br><span class="line">----before foreach----</span><br><span class="line">hello world</span><br><span class="line">Jia Gou Wu Dao</span><br><span class="line">----after foreach----</span><br><span class="line">----before peek and count----</span><br><span class="line">hello world</span><br><span class="line">Jia Gou Wu Dao</span><br><span class="line">----after peek and count----</span><br></pre></td></tr></table></figure></div>

<h3 id="filter、sorted、distinct、limit"><a href="#filter、sorted、distinct、limit" class="headerlink" title="filter、sorted、distinct、limit"></a>filter、sorted、distinct、limit</h3><p>这几个都是常用的Stream的中间操作方法，具体的方法的含义在上面的表格里面有说明。具体使用的时候，<strong>可以根据需要选择一个或者多个进行组合使用，或者同时使用多个相同方法的组合</strong>：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetTargetUsers</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>,<span class="string">&quot;10&quot;</span>,<span class="string">&quot;308&quot;</span>,<span class="string">&quot;49&quot;</span>,<span class="string">&quot;627&quot;</span>,<span class="string">&quot;193&quot;</span>,<span class="string">&quot;111&quot;</span>, <span class="string">&quot;193&quot;</span>);</span><br><span class="line">    <span class="comment">// 使用流操作</span></span><br><span class="line">    List&lt;Dept&gt; results = ids.stream()</span><br><span class="line">            .filter(s -&gt; s.length() &gt; <span class="number">2</span>)</span><br><span class="line">            .distinct()</span><br><span class="line">            .map(Integer::valueOf)</span><br><span class="line">            .sorted(Comparator.comparingInt(o -&gt; o))</span><br><span class="line">            .limit(<span class="number">3</span>)</span><br><span class="line">            .map(id -&gt; <span class="keyword">new</span> <span class="title class_">Dept</span>(id))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    System.out.println(results);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上面的代码片段的处理逻辑很清晰：</p>
<ol>
<li>使用filter过滤掉不符合条件的数据</li>
<li>通过distinct对存量元素进行去重操作</li>
<li>通过map操作将字符串转成整数类型</li>
<li>借助sorted指定按照数字大小正序排列</li>
<li>使用limit截取排在前3位的元素</li>
<li>又一次使用map将id转为Dept对象类型</li>
<li>使用collect终止操作将最终处理后的数据收集到list中</li>
</ol>
<p>输出结果：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[Dept&#123;id=111&#125;,  Dept&#123;id=193&#125;,  Dept&#123;id=205&#125;]</span><br></pre></td></tr></table></figure></div>

<h3 id="简单结果终止方法"><a href="#简单结果终止方法" class="headerlink" title="简单结果终止方法"></a>简单结果终止方法</h3><p>按照前面介绍的，终止方法里面像<code>count</code>、<code>max</code>、<code>min</code>、<code>findAny</code>、<code>findFirst</code>、<code>anyMatch</code>、<code>allMatch</code>、<code>nonneMatch</code>等方法，均属于这里说的简单结果终止方法。所谓简单，指的是其结果形式是数字、布尔值或者Optional对象值等。</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testSimpleStopOptions</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>, <span class="string">&quot;10&quot;</span>, <span class="string">&quot;308&quot;</span>, <span class="string">&quot;49&quot;</span>, <span class="string">&quot;627&quot;</span>, <span class="string">&quot;193&quot;</span>, <span class="string">&quot;111&quot;</span>, <span class="string">&quot;193&quot;</span>);</span><br><span class="line">    <span class="comment">// 统计stream操作后剩余的元素个数</span></span><br><span class="line">    System.out.println(ids.stream().filter(s -&gt; s.length() &gt; <span class="number">2</span>).count());</span><br><span class="line">    <span class="comment">// 判断是否有元素值等于205</span></span><br><span class="line">    System.out.println(ids.stream().filter(s -&gt; s.length() &gt; <span class="number">2</span>).anyMatch(<span class="string">&quot;205&quot;</span>::equals));</span><br><span class="line">    <span class="comment">// findFirst操作</span></span><br><span class="line">    ids.stream().filter(s -&gt; s.length() &gt; <span class="number">2</span>)</span><br><span class="line">            .findFirst()</span><br><span class="line">            .ifPresent(s -&gt; System.out.println(<span class="string">&quot;findFirst:&quot;</span> + s));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>执行后结果为：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">6</span><br><span class="line">true</span><br><span class="line">findFirst:205</span><br></pre></td></tr></table></figure></div>

<p><strong>避坑提醒</strong></p>
<p>这里需要补充提醒下，<strong>一旦一个Stream被执行了终止操作之后，后续便不可以再读这个流执行其他的操作</strong>了，否则会报错，看下面示例：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testHandleStreamAfterClosed</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>, <span class="string">&quot;10&quot;</span>, <span class="string">&quot;308&quot;</span>, <span class="string">&quot;49&quot;</span>, <span class="string">&quot;627&quot;</span>, <span class="string">&quot;193&quot;</span>, <span class="string">&quot;111&quot;</span>, <span class="string">&quot;193&quot;</span>);</span><br><span class="line">    Stream&lt;String&gt; stream = ids.stream().filter(s -&gt; s.length() &gt; <span class="number">2</span>);</span><br><span class="line">    <span class="comment">// 统计stream操作后剩余的元素个数</span></span><br><span class="line">    System.out.println(stream.count());</span><br><span class="line">    System.out.println(<span class="string">&quot;-----下面会报错-----&quot;</span>);</span><br><span class="line">    <span class="comment">// 判断是否有元素值等于205</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        System.out.println(stream.anyMatch(<span class="string">&quot;205&quot;</span>::equals));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    System.out.println(<span class="string">&quot;-----上面会报错-----&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>执行的时候，结果如下：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">6</span><br><span class="line">-----下面会报错-----</span><br><span class="line">java.lang.IllegalStateException: stream has already been operated upon or closed</span><br><span class="line">    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)</span><br><span class="line">    at java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:449)</span><br><span class="line">    at com.veezean.skills.stream.StreamService.testHandleStreamAfterClosed(StreamService.java:153)</span><br><span class="line">    at com.veezean.skills.stream.StreamService.main(StreamService.java:176)</span><br><span class="line">-----上面会报错-----</span><br></pre></td></tr></table></figure></div>

<p>因为stream已经被执行<code>count()</code>终止方法了，所以对stream再执行<code>anyMatch</code>方法的时候，就会报错<code>stream has already been operated upon or closed</code>，这一点在使用的时候需要特别注意。</p>
<h3 id="结果收集终止方法"><a href="#结果收集终止方法" class="headerlink" title="结果收集终止方法"></a>结果收集终止方法</h3><p>因为Stream主要用于对集合数据的处理场景，所以除了上面几种获取简单结果的终止方法之外，更多的场景是获取一个集合类的结果对象，比如List、Set或者HashMap等。</p>
<p>这里就需要<code>collect</code>方法出场了，它可以支持生成如下类型的结果数据：</p>
<ul>
<li>一个<code>集合类</code>，比如List、Set或者HashMap等</li>
<li>StringBuilder对象，支持将多个<code>字符串进行拼接</code>处理并输出拼接后结果</li>
<li>一个可以记录个数或者计算总和的对象（<code>数据批量运算统计</code>）</li>
</ul>
<h3 id="生成集合"><a href="#生成集合" class="headerlink" title="生成集合"></a>生成集合</h3><p>应该算是collect最常被使用到的一个场景了：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testCollectStopOptions</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;Dept&gt; ids = Arrays.asList(<span class="keyword">new</span> <span class="title class_">Dept</span>(<span class="number">17</span>), <span class="keyword">new</span> <span class="title class_">Dept</span>(<span class="number">22</span>), <span class="keyword">new</span> <span class="title class_">Dept</span>(<span class="number">23</span>));</span><br><span class="line">    <span class="comment">// collect成list</span></span><br><span class="line">    List&lt;Dept&gt; collectList = ids.stream().filter(dept -&gt; dept.getId() &gt; <span class="number">20</span>)</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    System.out.println(<span class="string">&quot;collectList:&quot;</span> + collectList);</span><br><span class="line">    <span class="comment">// collect成Set</span></span><br><span class="line">    Set&lt;Dept&gt; collectSet = ids.stream().filter(dept -&gt; dept.getId() &gt; <span class="number">20</span>)</span><br><span class="line">            .collect(Collectors.toSet());</span><br><span class="line">    System.out.println(<span class="string">&quot;collectSet:&quot;</span> + collectSet);</span><br><span class="line">    <span class="comment">// collect成HashMap，key为id，value为Dept对象</span></span><br><span class="line">    Map&lt;Integer, Dept&gt; collectMap = ids.stream().filter(dept -&gt; dept.getId() &gt; <span class="number">20</span>)</span><br><span class="line">            .collect(Collectors.toMap(Dept::getId, dept -&gt; dept));</span><br><span class="line">    System.out.println(<span class="string">&quot;collectMap:&quot;</span> + collectMap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>结果如下：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">collectList:[Dept&#123;id=22&#125;, Dept&#123;id=23&#125;]</span><br><span class="line">collectSet:[Dept&#123;id=23&#125;, Dept&#123;id=22&#125;]</span><br><span class="line">collectMap:&#123;22=Dept&#123;id=22&#125;, 23=Dept&#123;id=23&#125;&#125;</span><br></pre></td></tr></table></figure></div>

<h3 id="生成拼接字符串"><a href="#生成拼接字符串" class="headerlink" title="生成拼接字符串"></a>生成拼接字符串</h3><p><strong>将一个List或者数组中的值拼接到一个字符串里并以逗号分隔开</strong>，这个场景相信大家都不陌生吧？</p>
<p>如果通过<code>for</code>循环和<code>StringBuilder</code>去循环拼接，还得考虑下最后一个逗号如何处理的问题，很繁琐:</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testForJoinStrings</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>, <span class="string">&quot;10&quot;</span>, <span class="string">&quot;308&quot;</span>, <span class="string">&quot;49&quot;</span>, <span class="string">&quot;627&quot;</span>, <span class="string">&quot;193&quot;</span>, <span class="string">&quot;111&quot;</span>, <span class="string">&quot;193&quot;</span>);</span><br><span class="line">    <span class="type">StringBuilder</span> <span class="variable">builder</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">    <span class="keyword">for</span> (String id : ids) &#123;</span><br><span class="line">        builder.append(id).append(<span class="string">&#x27;,&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 去掉末尾多拼接的逗号</span></span><br><span class="line">    builder.deleteCharAt(builder.length() - <span class="number">1</span>);</span><br><span class="line">    System.out.println(<span class="string">&quot;拼接后：&quot;</span> + builder.toString());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>但是现在有了Stream，使用<code>collect</code>可以轻而易举的实现：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testCollectJoinStrings</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;String&gt; ids = Arrays.asList(<span class="string">&quot;205&quot;</span>, <span class="string">&quot;10&quot;</span>, <span class="string">&quot;308&quot;</span>, <span class="string">&quot;49&quot;</span>, <span class="string">&quot;627&quot;</span>, <span class="string">&quot;193&quot;</span>, <span class="string">&quot;111&quot;</span>, <span class="string">&quot;193&quot;</span>);</span><br><span class="line">    <span class="type">String</span> <span class="variable">joinResult</span> <span class="operator">=</span> ids.stream().collect(Collectors.joining(<span class="string">&quot;,&quot;</span>));</span><br><span class="line">    System.out.println(<span class="string">&quot;拼接后：&quot;</span> + joinResult);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>两种方式都可以得到完全相同的结果，但Stream的方式更优雅：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">拼接后：205,10,308,49,627,193,111,193</span><br></pre></td></tr></table></figure></div>

<h3 id="数据批量数学运算"><a href="#数据批量数学运算" class="headerlink" title="数据批量数学运算"></a>数据批量数学运算</h3><p>还有一种场景，实际使用的时候可能会比较少，就是使用collect生成数字数据的总和信息，也可以了解下实现方式：</p>
<div class="highlight-container" data-rel="Java"><figure class="iseeu highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testNumberCalculate</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;Integer&gt; ids = Arrays.asList(<span class="number">10</span>, <span class="number">20</span>, <span class="number">30</span>, <span class="number">40</span>, <span class="number">50</span>);</span><br><span class="line">    <span class="comment">// 计算平均值</span></span><br><span class="line">    <span class="type">Double</span> <span class="variable">average</span> <span class="operator">=</span> ids.stream().collect(Collectors.averagingInt(value -&gt; value));</span><br><span class="line">    System.out.println(<span class="string">&quot;平均值：&quot;</span> + average);</span><br><span class="line">    <span class="comment">// 数据统计信息</span></span><br><span class="line">    <span class="type">IntSummaryStatistics</span> <span class="variable">summary</span> <span class="operator">=</span> ids.stream().collect(Collectors.summarizingInt(value -&gt; value));</span><br><span class="line">    System.out.println(<span class="string">&quot;数据统计信息： &quot;</span> + summary);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

<p>上面的例子中，使用collect方法来对list中元素值进行数学运算，结果如下：</p>
<div class="highlight-container" data-rel="Tex"><figure class="iseeu highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">平均值：30.0</span><br><span class="line">总和：IntSummaryStatistics&#123;count=5, sum=150, min=10, average=30.000000, max=50&#125;</span><br></pre></td></tr></table></figure></div>

<h3 id="并行Stream"><a href="#并行Stream" class="headerlink" title="并行Stream"></a>并行Stream</h3><h5 id="1-机制说明"><a href="#1-机制说明" class="headerlink" title="1.机制说明"></a>1.机制说明</h5><p>使用并行流，可以有效利用计算机的多CPU硬件，提升逻辑的执行速度。并行流通过将一整个stream划分为<code>多个片段</code>，然后对各个分片流并行执行处理逻辑，最后将各个分片流的执行结果汇总为一个整体流。</p>
<p><strong><img lazyload src="/images/loading.svg" data-src="/sakura-blog/2023/01/09/%E5%90%83%E9%80%8FJAVA-Stream%E6%B5%81%E6%93%8D%E4%BD%9C/04.png" class title="图片"></strong></p>
<h5 id="2-约束与限制"><a href="#2-约束与限制" class="headerlink" title="2.约束与限制"></a>2.约束与限制</h5><p>并行流类似于多线程在并行处理，所以与多线程场景相关的一些问题同样会存在，比如死锁等问题，所以在并行流终止执行的函数逻辑，必须要保证<strong>线程安全</strong>。</p>
<h3 id="回答最初的问题"><a href="#回答最初的问题" class="headerlink" title="回答最初的问题"></a>回答最初的问题</h3><p><strong>Stream相较于传统的foreach的方式处理stream，到底有啥优势</strong>？</p>
<ul>
<li><strong>代码更简洁</strong>、偏声明式的编码风格，更容易体现出代码的逻辑意图</li>
<li><strong>逻辑间解耦</strong>，一个stream中间处理逻辑，无需关注上游与下游的内容，只需要按约定实现自身逻辑即可</li>
<li>并行流场景<strong>效率</strong>会比迭代器逐个循环更高</li>
<li>函数式接口，<strong>延迟执行</strong>的特性，中间管道操作不管有多少步骤都不会立即执行，只有遇到终止操作的时候才会开始执行，可以避免一些中间不必要的操作消耗</li>
</ul>
<p>当然了，Stream也不全是优点，在有些方面也有其弊端：</p>
<ul>
<li>代码调测debug不便</li>
<li>程序员从历史写法切换到Stream时，需要一定的适应时间</li>
</ul>
<p>但是，Stream流式操作数据，还是非常的优雅，且方便值得实际应用!!!</p>

            </div>

            
                <div class="post-copyright-info">
                    <div class="article-copyright-info-container">
    <ul>
        <li>本文标题：吃透JAVA_Stream流操作</li>
        <li>本文作者：Sakura</li>
        <li>创建时间：2023-01-09 11:25:27</li>
        <li>
            本文链接：https://xindong_a.gitee.io/sakura-blog/2023/01/09/吃透JAVA-Stream流操作/
        </li>
        <li>
            版权声明：本博客所有文章除特别声明外，均采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">BY-NC-SA</a> 许可协议。转载请注明出处！
        </li>
    </ul>
</div>

                </div>
            

            
                <ul class="post-tags-box">
                    
                        <li class="tag-item">
                            <a href="/sakura-blog/tags/java/">#java</a>&nbsp;
                        </li>
                    
                </ul>
            

            
                <div class="article-nav">
                    
                        <div class="article-prev">
                            <a class="prev"
                            rel="prev"
                            href="/sakura-blog/2023/01/09/%E9%AB%98%E5%B9%B6%E5%8F%91%E4%B8%8B%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E6%8E%A5%E5%8F%A3%E5%B9%82%E7%AD%89/"
                            >
                                <span class="left arrow-icon flex-center">
                                    <i class="fa-solid fa-chevron-left"></i>
                                </span>
                                <span class="title flex-center">
                                    <span class="post-nav-title-item">高并发下如何保证接口幂等?</span>
                                    <span class="post-nav-item">上一篇</span>
                                </span>
                            </a>
                        </div>
                    
                    
                        <div class="article-next">
                            <a class="next"
                            rel="next"
                            href="/sakura-blog/2023/01/09/%E7%BC%96%E7%A8%8B%E5%AE%9D%E8%97%8F%E8%80%81%E5%B8%88/"
                            >
                                <span class="title flex-center">
                                    <span class="post-nav-title-item">编程宝藏老师</span>
                                    <span class="post-nav-item">下一篇</span>
                                </span>
                                <span class="right arrow-icon flex-center">
                                    <i class="fa-solid fa-chevron-right"></i>
                                </span>
                            </a>
                        </div>
                    
                </div>
            

            
        </div>

        
            <div class="toc-content-container">
                <div class="post-toc-wrap">
    <div class="post-toc">
        <div style="font-size: 1.3rem;margin-top: 0; margin-bottom: 0.8rem; transition-duration: 0.1s;"><i class="fa-solid fa-list"></i> <strong>目录</strong></div>
        <ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#Stream%E5%88%9D%E7%9B%B8%E8%AF%86"><span class="nav-text">Stream初相识</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#map%E4%B8%8EflatMap"><span class="nav-text">map与flatMap</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#peek%E5%92%8Cforeach%E6%96%B9%E6%B3%95"><span class="nav-text">peek和foreach方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#filter%E3%80%81sorted%E3%80%81distinct%E3%80%81limit"><span class="nav-text">filter、sorted、distinct、limit</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%80%E5%8D%95%E7%BB%93%E6%9E%9C%E7%BB%88%E6%AD%A2%E6%96%B9%E6%B3%95"><span class="nav-text">简单结果终止方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%93%E6%9E%9C%E6%94%B6%E9%9B%86%E7%BB%88%E6%AD%A2%E6%96%B9%E6%B3%95"><span class="nav-text">结果收集终止方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%9F%E6%88%90%E9%9B%86%E5%90%88"><span class="nav-text">生成集合</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%9F%E6%88%90%E6%8B%BC%E6%8E%A5%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="nav-text">生成拼接字符串</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%95%B0%E6%8D%AE%E6%89%B9%E9%87%8F%E6%95%B0%E5%AD%A6%E8%BF%90%E7%AE%97"><span class="nav-text">数据批量数学运算</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B9%B6%E8%A1%8CStream"><span class="nav-text">并行Stream</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#1-%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E"><span class="nav-text">1.机制说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-%E7%BA%A6%E6%9D%9F%E4%B8%8E%E9%99%90%E5%88%B6"><span class="nav-text">2.约束与限制</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9B%9E%E7%AD%94%E6%9C%80%E5%88%9D%E7%9A%84%E9%97%AE%E9%A2%98"><span class="nav-text">回答最初的问题</span></a></li></ol>
    </div>
</div>
            </div>
        
    </div>
</div>


                

            </div>



        </div>

        <div class="page-main-content-bottom">
            <footer class="footer">
    <div class="info-container">
        <div class="copyright-info info-item">
            &copy;
            
              <span>2023</span>
              -
            
            2023&nbsp;<i class="fa-solid fa-heart icon-animate"></i>&nbsp;<a href="/">Sakura. 版权所有.</a>
        </div>
        
            <script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="website-count info-item">
                
                    <span id="busuanzi_container_site_uv">
                        访问人数&nbsp;<span id="busuanzi_value_site_uv"></span>&ensp;
                    </span>
                
                
                    <span id="busuanzi_container_site_pv">
                        总访问量&nbsp;<span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="theme-info info-item">
            由 <a target="_blank" href="https://hexo.io">Hexo</a> 驱动&nbsp;|&nbsp;主题&nbsp;<a class="theme-version" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v0.4.6</a>
        </div>
        
        
        <script async data-pjax defer>
            function odometer_init(){
                    let el = document.getElementsByClassName('odometer');
                    for (i = 0; i < el.length; i++) {
                        od = new Odometer({
                            el: el[i],
                            format: '( ddd).dd',
                            duration: 200
                        });
                    }
            }
            odometer_init();
        </script>
        <div id="start_time_div" style="display:none">
            2023/1/4 12:00:00
        </div>
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
        
    </div>  
</footer>
        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="tools-list">
        <!-- TOC aside toggle -->
        
            <li class="tools-item page-aside-toggle">
                <i class="fa-regular fa-outdent"></i>
            </li>
        

        <!-- go comment -->
        
    </ul>
</div>

        </div>
    

    <div class="right-bottom-side-tools">
        <div class="side-tools-container">
    <ul class="side-tools-list">
        <li class="tools-item tool-font-adjust-plus flex-center">
            <i class="fa-solid fa-magnifying-glass-plus"></i>
        </li>

        <li class="tools-item tool-font-adjust-minus flex-center">
            <i class="fa-solid fa-magnifying-glass-minus"></i>
        </li>

        <li class="tools-item tool-expand-width flex-center">
            <i class="fa-solid fa-left-right"></i>
        </li>

        <li class="tools-item tool-dark-light-toggle flex-center">
            <i class="fa-solid fa-moon"></i>
        </li>

        <!-- rss -->
        

        
            <li class="tools-item tool-scroll-to-top flex-center">
                <i class="fa-solid fa-arrow-up"></i>
            </li>
        

        <li class="tools-item tool-scroll-to-bottom flex-center">
            <i class="fa-solid fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="exposed-tools-list">
        <li class="tools-item tool-toggle-show flex-center">
            <i class="fa-solid fa-cog fa-spin"></i>
        </li>
        
    </ul>
</div>

    </div>

    <div class="image-viewer-container">
    <img src="">
</div>


    

</main>




<script src="/sakura-blog/js/utils.js"></script>

<script src="/sakura-blog/js/main.js"></script>

<script src="/sakura-blog/js/header-shrink.js"></script>

<script src="/sakura-blog/js/back2top.js"></script>

<script src="/sakura-blog/js/dark-light-toggle.js"></script>





    
<script src="/sakura-blog/js/code-copy.js"></script>




    
<script src="/sakura-blog/js/lazyload.js"></script>




    
<script src="/sakura-blog/js/runtime.js"></script>

    
<script src="/sakura-blog/js/odometer.min.js"></script>

    
<link rel="stylesheet" href="/sakura-blog/css/odometer-theme-minimal.css">



<div class="post-scripts pjax">
    
        
<script src="/sakura-blog/js/toc-toggle.js"></script>

<script src="/sakura-blog/js/libs/anime.min.js"></script>

<script src="/sakura-blog/js/toc.js"></script>

    
</div>


    
<script src="/sakura-blog/js/libs/pjax.min.js"></script>

<script>
    window.addEventListener('DOMContentLoaded', () => {
        window.pjax = new Pjax({
            selectors: [
                'head title',
                '.page-container',
                '.pjax'
            ],
            history: true,
            debug: false,
            cacheBust: false,
            timeout: 0,
            analytics: false,
            currentUrlFullReload: false,
            scrollRestoration: false,
            // scrollTo: true,
        });

        document.addEventListener('pjax:send', () => {
            REDEFINE.utils.pjaxProgressBarStart();
        });

        document.addEventListener('pjax:complete', () => {
            REDEFINE.utils.pjaxProgressBarEnd();
            window.pjax.executeScripts(document.querySelectorAll('script[data-pjax], .pjax script'));
            REDEFINE.refresh();
        });
    });
</script>



</body>
</html>
